from typing import List
from sympy import Matrix

def matrix_mul(m1: List, m2: List) -> List:
    '''
    矩阵乘法
    输入 矩阵一 矩阵二
    返回 矩阵一右乘矩阵二相乘结果
    '''
    # 先判断是数乘还是矩阵乘法
    if(type(m1) == int):
        return ( m1 * Matrix(m2) ).tolist()
    
    if(type(m2) == int):
        return ( Matrix(m1) * m1 ).tolist()

    return ( Matrix(m1) * Matrix(m2) ).tolist()

def matrix_add(m1: List, m2: List) -> List:
    '''
    矩阵加法
    输入 矩阵一 矩阵二
    返回 矩阵一加矩阵二结果
    '''
    return ( Matrix(m1) + Matrix(m2) ).tolist()

def matrix_sub(m1: List, m2: List) -> List:
    '''
    矩阵减法
    输入 矩阵一 矩阵二
    返回 矩阵一减矩阵二结果
    '''
    return ( Matrix(m1) - Matrix(m2) ).tolist()

def matrix_tran(m: List) -> List:
    '''
    矩阵转置
    输入 矩阵
    返回 矩阵转置 结果
    '''
    return Matrix(m).T.tolist()

def matrix_inv(m: List) -> List:
    '''
    矩阵求逆
    输入 矩阵
    返回 逆矩阵 
    '''
    return (Matrix(m) ** (-1)).tolist()

def get_pc(cm: List) -> List:
    '''
    获取矩阵的最大特征值的特征向量作为主分量
    输入 矩阵
    返回 矩阵最大特征值对应的特征向量
    '''
    return sorted(Matrix(cm).eigenvects(),key= lambda x: -x[0])[0][2][0].tolist()

def get_aver(samples: List[List]) -> List:
    '''
    获取样本集的均值
    输入 样本集 形如 [ [1,1], [1,2], [1,3] ]
    返回 样本集均值
    '''
    return [sum([samples[i][d] for i in range(len(samples))])/len(samples) for d in range(len(samples[0]))]


def get_cm(vects: List[List]) -> List:
    '''
    求解样本集的协方差矩阵
    输入 样本集 形如 [ [1,1], [1,2], [1,3] ]
    返回 协方差矩阵
    '''
    aver = get_aver(vects)
    
    res = matrix_mul(matrix_sub(vects[0],aver), matrix_tran(matrix_sub(vects[0],aver))) 

    for v in vects[1:]:
        res = matrix_add(res,matrix_mul(matrix_sub(v,aver), matrix_tran(matrix_sub(v,aver))))
    return (Matrix(res)/len(vects)).tolist()



# for debug

# x1 = [[10,1]]
# x2 = [[9,0]]
# x3 = [[10,-1]]
# x4 = [[11,0]]
# x5 = [[0,9]]
# x6 = [[1,10]]
# x7 = [[0,11]]
# x8 = [[-1,10]]

# xs = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8
# con = get_cm(xs)
# aver = [get_aver(xs)]
# print(aver)
# pc = get_pc(con)
# print(pc)
# print(matrix_sub(x1,aver))
# print(matrix_mul(matrix_sub(x1,aver),pc))
# print(9/2*(2**(1/2)))

# a = [ [-3,-2.83] ]
# print( matrix_mul(4, matrix_mul(matrix_tran(a),a)) )